unit Spring.XE.Interceptor;

interface

uses Winapi.Windows, System.Classes, System.SysUtils, System.Rtti, System.Generics.Collections;

type
  TSpringInterceptor = class(TInterfacedPersistent)
  private
    FInterceptor: TVirtualMethodInterceptor;
    FClass: TClass;
    FInstanceList: TList<TObject>;
  protected
    procedure InterceptBeforeNotify(Instance: TObject;
      Method: TRttiMethod; const Args: TArray<TValue>; out DoInvoke: Boolean;
      out Result: TValue); virtual;
    procedure InterceptAfterNotify(Instance: TObject;
      Method: TRttiMethod; const Args: TArray<TValue>; var Result: TValue); virtual;
    procedure InterceptExceptionNotify(Instance: TObject;
      Method: TRttiMethod; const Args: TArray<TValue>; out RaiseException: Boolean;
      TheException: Exception; out Result: TValue); virtual;
  public
    procedure Interceptor(const AInstance: TObject);
    procedure UnInterceptor(const AInstance: TObject);
    constructor Create(const ADestClassName: string);
    destructor Destroy; override;
  end;

implementation

{ TSpringInterceptor }

constructor TSpringInterceptor.Create(const ADestClassName: string);
var
  oRTTI: TRttiContext;
  oType: TRttiType;
begin
  oType := oRTTI.FindType(ADestClassName);
  FClass := oType.AsInstance.MetaclassType;
  FInstanceList := TList<TObject>.Create;
  FInterceptor := TVirtualMethodInterceptor.Create(FClass);
  FInterceptor.OnBefore := InterceptBeforeNotify;
  FInterceptor.OnAfter := InterceptAfterNotify;
  FInterceptor.OnException := InterceptExceptionNotify;
end;

destructor TSpringInterceptor.Destroy;
begin
  FInterceptor.Free;
  inherited;
end;

procedure TSpringInterceptor.Interceptor(const AInstance: TObject);
begin
  FInterceptor.Proxify(AInstance);
  FInstanceList.Add(AInstance);
end;

procedure TSpringInterceptor.UnInterceptor(const AInstance: TObject);
var
  nIndex: Integer;
begin
  FInterceptor.Unproxify(AInstance);
  nIndex := FInstanceList.IndexOf(AInstance);
  if nIndex >= 0 then
    FInstanceList.Delete(nIndex);
end;

procedure TSpringInterceptor.InterceptAfterNotify(Instance: TObject; Method: TRttiMethod;
  const Args: TArray<TValue>; var Result: TValue);
begin
  OutputDebugString('>>>>>InterceptAfterNotify');
end;

procedure TSpringInterceptor.InterceptBeforeNotify(Instance: TObject; Method: TRttiMethod;
  const Args: TArray<TValue>; out DoInvoke: Boolean; out Result: TValue);
begin
  OutputDebugString('>>>>>InterceptBeforeNotify');
end;

procedure TSpringInterceptor.InterceptExceptionNotify(Instance: TObject; Method: TRttiMethod;
  const Args: TArray<TValue>; out RaiseException: Boolean; TheException: Exception;
  out Result: TValue);
begin
  OutputDebugString('>>>>>InterceptExceptionNotify');
end;

end.
